use std::sync::LazyLock;

use argon2::{
    Argon2,
    password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString, rand_core::OsRng},
};

static ARGON2: LazyLock<Argon2> = LazyLock::new(|| Argon2::default());

/// Hashes input password.
/// This action is highly time consuming. Because Argon2 is a memory- and CPU-intensive hashing algorithm designed specifically to slow down brute-force attacks.
pub fn hash_password(password: &str) -> String {
    // Generates salt string.
    let salt = SaltString::generate(&mut OsRng);

    // Argon2 with default params (Argon2id v19).
    // let argon2 = Argon2::default();

    // Hashes password to PHC string.
    let password_hash = ARGON2
        .hash_password(password.as_bytes(), &salt)
        .unwrap()
        .to_string();

    password_hash
}

/// Verifies input password and password_hash.
/// This action is highly time consuming. Because Argon2 is a memory- and CPU-intensive hashing algorithm designed specifically to slow down brute-force attacks.
pub fn verify_password(password: &str, password_hash: &str) -> bool {
    let parsed_hash = PasswordHash::new(password_hash).unwrap();

    ARGON2
        .verify_password(password.as_bytes(), &parsed_hash)
        .is_ok()
}

// pub async fn verify_password(password: &str, password_hash: &str) -> bool {
//     // Clones the password and password_hash to move ownership into the closure.
//     let password = password.to_owned();
//     let password_hash = password_hash.to_owned();

//     task::spawn_blocking(move || {
//         let parsed_hash = PasswordHash::new(&password_hash).unwrap();

//         Argon2::default()
//             .verify_password(password.as_bytes(), &parsed_hash)
//             .is_ok()
//     })
//     .await
//     .unwrap_or(false)
// }
